<!DOCTYPE html>
<html>
<head>
    <title>Logic Gate Diagram</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
        }
        canvas {
            border: 1px solid #ccc;
            background-color: white;
        }
    </style>
</head>
<body>
    <canvas id="logicGateCanvas" width="500" height="450"></canvas>
    <script>
        const canvas = document.getElementById('logicGateCanvas');
        const ctx = canvas.getContext('2d');

        // --- Drawing styles and parameters ---
        ctx.strokeStyle = 'black';
        ctx.fillStyle = 'black';
        ctx.lineWidth = 2.5;
        const gateWidth = 50;
        const gateHeight = 40;
        const lineLength = 30;
        const bubbleRadius = 4.5;
        
        const col1_x = 140;
        const col2_x = 360;
        const row_start_y = 80;
        const row_spacing = 90;

        // --- Helper function to draw a generic 2-input gate ---
        function drawGate(config) {
            const { cx, cy, label, invertInput1, invertInput2, invertOutput } = config;
            
            // Draw Label
            ctx.font = 'bold 22px serif';
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillText(label, cx - gateWidth / 2 - lineLength - 20, cy);

            // Gate Body (D-shape)
            const bodyLeft = cx - gateWidth / 2;
            ctx.beginPath();
            ctx.moveTo(bodyLeft, cy - gateHeight / 2);
            ctx.lineTo(bodyLeft + gateWidth, cy - gateHeight / 2);
            ctx.arc(bodyLeft + gateWidth, cy, gateHeight / 2, -Math.PI / 2, Math.PI / 2);
            ctx.lineTo(bodyLeft, cy + gateHeight / 2);
            ctx.closePath();
            // Fill with white to hide any lines that might accidentally cross it
            const currentFillStyle = ctx.fillStyle;
            ctx.fillStyle = 'white';
            ctx.fill();
            ctx.fillStyle = currentFillStyle;
            ctx.stroke();

            // Input Lines
            const inputY1 = cy - gateHeight / 4;
            const inputY2 = cy + gateHeight / 4;
            
            // Input 1 (top)
            let input1End = bodyLeft;
            if (invertInput1) {
                ctx.beginPath();
                ctx.arc(bodyLeft - bubbleRadius, inputY1, bubbleRadius, 0, 2 * Math.PI);
                ctx.fillStyle = 'white';
                ctx.fill();
                ctx.stroke();
                input1End -= 2 * bubbleRadius;
            }
            ctx.beginPath();
            ctx.moveTo(input1End, inputY1);
            ctx.lineTo(input1End - lineLength, inputY1);
            ctx.stroke();

            // Input 2 (bottom)
            let input2End = bodyLeft;
            if (invertInput2) {
                ctx.beginPath();
                ctx.arc(bodyLeft - bubbleRadius, inputY2, bubbleRadius, 0, 2 * Math.PI);
                ctx.fillStyle = 'white';
                ctx.fill();
                ctx.stroke();
                input2End -= 2 * bubbleRadius;
            }
            ctx.beginPath();
            ctx.moveTo(input2End, inputY2);
            ctx.lineTo(input2End - lineLength, inputY2);
            ctx.stroke();

            // Output Line
            const outputX = bodyLeft + gateWidth + gateHeight / 2;
            let outputStart = outputX;
            if (invertOutput) {
                ctx.beginPath();
                ctx.arc(outputX + bubbleRadius, cy, bubbleRadius, 0, 2 * Math.PI);
                ctx.fillStyle = 'white';
                ctx.fill();
                ctx.stroke();
                outputStart += 2 * bubbleRadius;
            }
            ctx.beginPath();
            ctx.moveTo(outputStart, cy);
            ctx.lineTo(outputStart + lineLength, cy);
            ctx.stroke();
        }

        // --- Draw all 8 gates ---
        // Column 1
        drawGate({ cx: col1_x, cy: row_start_y, label: '1', invertInput1: false, invertInput2: false, invertOutput: false }); // AND
        drawGate({ cx: col1_x, cy: row_start_y + row_spacing, label: '2', invertInput1: false, invertInput2: false, invertOutput: true }); // NAND
        drawGate({ cx: col1_x, cy: row_start_y + 2 * row_spacing, label: '3', invertInput1: false, invertInput2: false, invertOutput: false }); // AND
        drawGate({ cx: col1_x, cy: row_start_y + 3 * row_spacing, label: '4', invertInput1: false, invertInput2: false, invertOutput: true }); // NAND

        // Column 2
        drawGate({ cx: col2_x, cy: row_start_y, label: '5', invertInput1: true, invertInput2: true, invertOutput: false }); // NOR
        drawGate({ cx: col2_x, cy: row_start_y + row_spacing, label: '6', invertInput1: false, invertInput2: false, invertOutput: false }); // AND
        drawGate({ cx: col2_x, cy: row_start_y + 2 * row_spacing, label: '7', invertInput1: true, invertInput2: true, invertOutput: true }); // OR
        drawGate({ cx: col2_x, cy: row_start_y + 3 * row_spacing, label: '8', invertInput1: false, invertInput2: false, invertOutput: false }); // AND

        // --- Draw Caption ---
        ctx.fillStyle = 'black';
        ctx.font = 'bold 24px serif';
        ctx.textAlign = 'center';
        ctx.fillText('Fig. 3.66', canvas.width / 2, 425);
    </script>
</body>
</html>